home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / OpenDoc 1.2b2c1 / Implementation / Utilities / SEUtils.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-13  |  29.9 KB  |  1,011 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        SEUtils.cpp
  3.  
  4.     Contains:    xxx put contents here xxx
  5.  
  6.     Owned by:    Jon Pugh
  7.  
  8.     Copyright:    © 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <6>      12/13/96    JP        1611571: Renamed parameter
  13.          <5>     9/27/96    TJ        Added Includes
  14.          <4>     9/26/96    JP        1372897: Added CompareDescs utility.
  15.          <3>     9/24/96    TJ        Added Includes
  16.          <2>     9/23/96    JP        1384958: Moved routines from SEPriv.cpp,
  17.                                     renamed GetDefaultRootFrame & added
  18.                                     ShouldHandleEvent
  19.  
  20.     To Do:
  21. */
  22.  
  23. /*
  24.     File:        SEUtils.cpp
  25.  
  26.     Contains:    Semantic Event Utility Functions implementation.
  27.  
  28.     Owned by:    Nick Pilch
  29.  
  30.     Copyright:    © 1993 - 1995 by Apple Computer, Inc., all rights reserved.
  31.  
  32.     
  33.         
  34. */
  35.  
  36. #ifndef __ERRORS__
  37. #include <Errors.h>
  38. #endif
  39.  
  40. #ifndef _ODDESUTL_
  41. #include <ODDesUtl.h>
  42. #endif
  43.  
  44. #ifndef SOM_ODFrame_xh
  45. #include <Frame.xh>
  46. #endif
  47.  
  48. #ifndef _ODDEBUG_
  49. #include "ODDebug.h"
  50. #endif
  51.  
  52. #ifndef SOM_ODAppleEvent_xh
  53. #include "ODAplEvt.xh"
  54. #endif
  55.  
  56. #ifndef SOM_ODOSLToken_xh
  57. #include "ODOSLTkn.xh"
  58. #endif
  59.  
  60. #ifndef SOM_ODNameResolver_xh
  61. #include "NamRslvr.xh"
  62. #endif
  63.  
  64. #ifndef __FILES__
  65. #include <Files.h>
  66. #endif
  67.  
  68. #ifndef _EXCEPT_
  69. #include "Except.h"
  70. #endif
  71.  
  72. #ifndef _ODMEMORY_
  73. #include "ODMemory.h"
  74. #endif
  75.  
  76. #ifndef __STRING__
  77. #include <string.h>
  78. #endif
  79.  
  80. #ifndef __STDLIB__
  81. #include <stdlib.h>
  82. #endif
  83.  
  84. #ifndef __QUICKDRAW__
  85. #include <Quickdraw.h>
  86. #endif
  87.  
  88. #ifndef __AEOBJECTS__
  89. #include <AEObjects.h>
  90. #endif
  91.  
  92. #pragma segment ODSEUtils
  93.  
  94. #ifndef _SEUTILS_
  95. #include "SEUtils.h"
  96. #endif
  97.  
  98. #ifndef SOM_ODSession_xh
  99. #include "ODSessn.xh"
  100. #endif
  101.  
  102. #ifndef SOM_ODWindowState_xh
  103. #include <WinStat.xh>
  104. #endif
  105.  
  106. #ifndef SOM_ODWindow_xh
  107. #include <Window.xh>
  108. #endif
  109.  
  110. #ifndef SOM_Module_OpenDoc_ODRegistry_defined
  111. #include "ODRgstry.xh"
  112. #endif
  113.  
  114. #ifndef _SIHLPABS_
  115. #include "SIHlpAbs.h"
  116. #endif
  117.  
  118. #ifndef _TEMPITER_
  119. #include "TempIter.h"
  120. #endif
  121.  
  122. #ifndef SOM_ODEmbeddedFramesIterator_xh
  123. #include "EmbFrItr.xh"
  124. #endif
  125.  
  126. #ifndef _ODUTILS_
  127. #include <ODUtils.h>
  128. #endif
  129.  
  130. #ifndef SOM_Module_OpenDoc_StdDefs_defined
  131. #include <StdDefs.xh>
  132. #endif
  133.  
  134. #ifndef SOM_ODObjectSpec_xh
  135. #include "ODObjSpc.xh"
  136. #endif
  137.  
  138. #ifndef __ASREGISTRY__
  139. #include <ASRegistry.h>
  140. #endif
  141.  
  142. #ifndef __TEXTUTILS__
  143. #include <TextUtils.h>
  144. #endif
  145.  
  146. OSErr MyAECoerceDescPtr(AEDesc theAEDesc, DescType toType, Ptr dataPtr,
  147.                         Size maximumSize, Size* actualSize);
  148. long MyRandom(long count);
  149.  
  150. ODBoolean MissingParams(const AppleEvent* message)
  151. {
  152.     AEKeyword     missedKeyword;
  153.     DescType    ignoreType;
  154.     Size        ignoreSize;
  155.     OSErr         myErr;
  156.     
  157.     myErr = AEGetAttributePtr(message, keyMissedKeywordAttr, typeWildCard,
  158.                                 &ignoreType, (Ptr)&missedKeyword,
  159.                                 sizeof(missedKeyword), &ignoreSize);
  160.     return myErr == noErr;
  161. }
  162.  
  163. /* -- I've made this a memeber function of ODApplicatiin (in Shell.cp)
  164. // HEY! This function assumes that typeCode is typeChar and toType is typeFSS.
  165. //pascal OSErr Pathname2FSSpec(DescType        typeCode,
  166. //                                Ptr            dataPtr,
  167. //                                Size        dataSize,
  168. //                                DescType    toType,
  169. //                                long        handlerRefCon,
  170. //                                AEDesc*        result)
  171.  
  172.  
  173. // ODDescCoercionHandler 
  174. void Pathname2FSSpec(    ODPart* thePart, DescType typeCode, Ptr dataPtr,
  175.                         Size dataSize, DescType    toType, long handlerRefCon,
  176.                         AEDesc*     result)
  177. {
  178.     Str255        fileName;
  179.     FSSpec        fileSpec;
  180.     const short    kNoVRefNum = 0;
  181.     const long    kNoDirID = 0;
  182.     OSErr        error;
  183.     
  184.     if (dataSize > sizeof(Str255))
  185.         return bdNamErr;
  186.  
  187.     ODBlockMove(dataPtr, fileName + 1, dataSize);
  188.     fileName[0] = (unsigned char)dataSize;
  189.  
  190.     error = FSMakeFSSpec(kNoVRefNum, kNoDirID, fileName, &fileSpec);
  191.     THROW_IF_ERROR( error );
  192.     
  193.     error = AECreateDesc(typeFSS, (Ptr) &fileSpec, sizeof(fileSpec), result);
  194.     THROW_IF_ERROR( error );
  195. }
  196.  
  197. */
  198.  
  199. /*
  200. The following functions were lifted from Quill.p and translated
  201. */
  202.  
  203. #define genericErr (-1799)
  204. #define errAEBadData (-15310)
  205. Size gActSize;
  206.  
  207.  
  208. OSErr DecodeOrdinal(AEDesc ordData, long count, long* index,
  209.                     Boolean* allFlag, Boolean* zeroFlag)
  210. /* this routine is used whenever an element is specified by an absolute position
  211.   within a sequence of elements - such as "word 3 of window 'johnson'", "any line
  212.   of item 17 of window 'Kelvin'", etc.  The data specifying the position can be
  213.   a positive integer (which just means the actual position of the element in the
  214.   sequence: 1 for the first element, 2 for the second, etc.), a negative integer
  215.   (which indicates position relative to the last element of the sequence: -1 is
  216.   the last element, -2 the next to last, etc.), or a descriptor of typeAbsoluteOrdinal:
  217.   kAEFirst, kAELast, kAEMiddle, kAEAny, or kAEAll.  
  218.   
  219.   DecodeOrdinal takes the data specifying the position, and a count of all the elements
  220.   in the sequence under consideration, and returns (whenever possible) a positive integer
  221.   (in the return VAR index) representing the actual position of the element in the sequence 
  222.   (1 for first, 2 for second, etc.).  It also returns flags indicating (a) whether the 
  223.   ordinal was kAEAll and (b) whether the count was 0; both of these are conditions that 
  224.   many calling routines will have to special-case.  In the case of kAEAll, the return VAR 
  225.   index is set to the count; in the case of count = 0, the return VAR index is set to 0.
  226.   
  227.   There are a few error conditions:  (a) count < 0; (b) bad ordData (not an integer, and
  228.   not one of the five defined absolute ordinal specifiers).  **CHECK - should "integer ordData
  229.   out of range" (for example, an integer > count, or < -count, or = 0) be an error,
  230.   or should we allow that so that people can talk about "the hypothetical element
  231.   beyond the last", or whatever?  For now, let's make that a non-error.
  232.   
  233.   INPUTS:    ordData        a descriptor that specifies an ordinal - either
  234.                           an integer (positive or negative) or something
  235.                         of typeAbsoluteOrdinal
  236.             count        the total number of elements in the group involved
  237.                         (number of windows, number or chars, or whatever)
  238.             index        return VAR for the actual position being described
  239.             allFlag        return VAR: TRUE if the ordData was kAEAll, FALSE o.w.
  240.             zeroFlag    return VAR: TRUE if the count was zero (for many
  241.                         calling routines this is an error condition), FALSE o.w.
  242.   OUTPUTS:    error code (noErr if none)
  243. */
  244. {
  245.     OSErr myErr;
  246.     DescType absOrd;
  247.     long intOrd;
  248.  
  249.   myErr = genericErr;
  250.   *index = count;
  251.   *allFlag = kODFalse;
  252.   
  253.   *zeroFlag = (count == 0);
  254.   if (count < 0)
  255.   {
  256.       myErr = errAEBadData;
  257.       goto exit;
  258.     }
  259.   
  260.   myErr = MyAECoerceDescPtr(ordData, typeAbsoluteOrdinal, (Ptr)&absOrd,
  261.                               sizeof(absOrd), &gActSize);
  262.   if (myErr == noErr)
  263.     {
  264.       /* got an absolute ordinal */
  265.       /* note that, as we enter here, index == count and myErr == noErr */
  266.       *allFlag = (absOrd == kAEAll);
  267.       if (*allFlag)
  268.           goto exit;    /* finish up */
  269.         
  270.       if ((absOrd != kAEFirst) && (absOrd != kAELast)
  271.               && (absOrd != kAEMiddle) && (absOrd != kAEAny))
  272.         {
  273.           myErr = errAEBadData;
  274.           goto exit;
  275.         }
  276.         
  277.       if (*zeroFlag || (absOrd == kAELast))
  278.           goto exit; /* in both cases, index == count (already done) */
  279.         
  280.       if (absOrd == kAEFirst)
  281.           *index = 1;
  282.       else if (absOrd == kAEMiddle)
  283.           *index = (count + 1) / 2;
  284.       else
  285.           *index = MyRandom(count);
  286.       
  287.       goto exit;
  288.     }    /* of absolute ordinal */
  289.     
  290.   /* try actual integer */
  291.   myErr = MyAECoerceDescPtr(ordData, typeLongInteger, (Ptr)&intOrd,
  292.                                   sizeof(intOrd), &gActSize);
  293.   if (myErr)
  294.     goto exit;
  295.       
  296.   if (intOrd < 0)
  297.       *index = count + intOrd + 1;    /* e.g., intOrd == -1 means index == count */
  298.   else
  299.       *index = intOrd;
  300.   
  301.   /* should we validate index here (wrt count)?  let's skip it for now */
  302.   
  303. exit:    /* finish up */
  304.   return myErr;
  305. }
  306.  
  307. OSErr MyAECoerceDescPtr(AEDesc theAEDesc, DescType toType, Ptr dataPtr,
  308.                         Size maximumSize, Size* actualSize)
  309. /* this routine plugs a hole that's been nagging at me in the AppleEvents
  310.   interface.  It takes a descriptor and coerces it to a desired type; but
  311.   instead of returning a descriptor, it returns data in a buffer specified
  312.   by the caller.
  313.   INPUTS:    theAEDesc        descriptor to be coerced
  314.               toType            type to coerce it to
  315.             dataPtr            ptr to data buffer
  316.             maximumSize        maximum length in bytes of data to be returned
  317.             actualSize        actual length in bytes of data for the descriptor
  318.   OUTPUTS:    error code (noErr if none)
  319.   ERRORS:
  320.   SIDE EFFECTS:
  321.   NOTES:    12/16/91    BHM        (1) Changed to avoid unecessary duplication when the type
  322.                                   doesn't really change (this should also enable it to handle
  323.                                 typeWildCard better)
  324.                                 (2) We don't need to dispose of newDesc because it is a direct
  325.                                 copy (not a duplicate) of either theAEDesc or resultDesc - that
  326.                                 is, it contains the same handle
  327.             03/12/92    BHM        Added special case to deal with NIL data handles (which should only 
  328.                                 occur for typeNull, I believe)
  329. */
  330. {
  331.     short myErr;
  332.     AEDesc newDesc;
  333.     AEDesc resultDesc = NULL_DESCRIPTOR_DEFINITION;
  334.     Size transferSize;
  335.  
  336.   myErr = errAECoercionFail;
  337.   
  338.   /* to avoid unnecessary duplication, check old type vs. new type */
  339.   if ((theAEDesc.descriptorType == toType) || (toType == typeWildCard))
  340.       newDesc = theAEDesc;
  341.   else
  342.     {
  343.       /* must coerce to new type */
  344.       myErr = AECoerceDesc(&theAEDesc, toType, &resultDesc); 
  345.       if (myErr)
  346.           goto exit;
  347.       newDesc = resultDesc;
  348.     }
  349.         
  350. //  WITH newDesc DO
  351.     {
  352.       /* special-case for NIL handle */    /* should I **CHECK to make sure it's typeNull here? */
  353.       if (newDesc.dataHandle == kODNULL)
  354.         {
  355.           actualSize = 0;
  356.           myErr = noErr;
  357.           goto exit;
  358.         }
  359.         
  360.       /* not NIL handle - get the size */
  361.       *actualSize = ODGetHandleSize((ODHandle)newDesc.dataHandle);
  362.         myErr = MemError();
  363.         if (myErr)
  364.               goto exit;
  365.     
  366.       /* calculate number of bytes to move */
  367.       transferSize = *actualSize;
  368.       if (maximumSize < transferSize)
  369.           transferSize = maximumSize;
  370.     
  371.       /* move the data */
  372. //      HLock(newDesc.dataHandle);
  373.       ODBlockMove(*(newDesc.dataHandle), dataPtr, transferSize);
  374. //      HUnlock(newDesc.dataHandle);
  375.     }    /* of WITH newDesc */
  376.     
  377.   /* everything fine */
  378.   myErr = noErr;
  379.     
  380. exit:    /* finish up */
  381.   AEDisposeDesc(&resultDesc);
  382.   return myErr;
  383. }    /* MyAECoerceDescPtr */
  384.  
  385. long MyRandom(long count)
  386. /* return a random integer between 1 and count, inclusive
  387.   INPUTS:    count        upper bound for random number
  388.   OUTPUTS:    a random integer between 1 and count, inclusive
  389.   NOTES:    **CHECK - this is a quick, dirty, and WRONG version
  390.               to be used for testing only
  391. */
  392. {
  393. long longRandom;
  394.  
  395.   longRandom = 0x10000*Random() + Random();
  396.   return (labs(longRandom) % count) + 1;
  397. }    /* MyRandom */
  398.  
  399. //------------------------------------------------------------------------------
  400. // GetSLongAttr
  401. //------------------------------------------------------------------------------
  402.  
  403. ODSLong GetSLongAttr(AppleEvent* ae, AEKeyword keyword)
  404. {
  405.     OSErr        result;
  406.     ODSLong    value;
  407.     DescType    actualType;
  408.     Size        sizeOfBuffer = sizeof(value);
  409.     Size        actualSize;
  410.  
  411.     result = AEGetAttributePtr(ae, keyword, typeWildCard, &actualType,
  412.                                     (Ptr)&value, sizeOfBuffer, &actualSize);
  413.     if (result != noErr)
  414.         THROW((ODError)result);
  415.     //if ((actualType != typeShortInteger) || (actualSize != sizeOfBuffer))
  416.     if (actualSize != sizeOfBuffer)
  417.         THROW(kODErrOutOfMemory);
  418.         
  419.     return value;
  420. }
  421.  
  422. //------------------------------------------------------------------------------
  423. // GetSLongAttrOD
  424. //------------------------------------------------------------------------------
  425.  
  426. ODSLong GetSLongAttrOD(ODAppleEvent* ae, AEKeyword keyword)
  427. {
  428.     AppleEvent realAE;
  429.     THROW_IF_ERROR( ODDescToAEDesc( ae, &realAE ) ) ;
  430.     ODSLong result = GetSLongAttr( &realAE, keyword );
  431.     (void)AEDisposeDesc( &realAE );
  432.     return result;
  433. }
  434.  
  435. //------------------------------------------------------------------------------
  436. // ThrowIfCantCoerce
  437. //------------------------------------------------------------------------------
  438.  
  439. // does an in-place coercion!
  440. void ThrowIfCantCoerce( AEDesc* data, DescType desiredType )
  441. {
  442.     if ( data->descriptorType == desiredType )
  443.         return ;
  444.  
  445.     AEDesc newDesc ;
  446.     THROW_IF_ERROR( AECoerceDesc( data, desiredType, &newDesc ) ) ;
  447.     AEDisposeDesc( data ) ;
  448.     *data = newDesc ;
  449. }
  450.  
  451. //------------------------------------------------------------------------------
  452. // ThrowIfNotAbsent
  453. //------------------------------------------------------------------------------
  454.  
  455. void ThrowIfNotAbsent( OSErr err )
  456. {
  457.     if ( (err == noErr) || ( err == errAEDescNotFound ) )
  458.         return ;
  459.     THROW( err ) ;
  460. }
  461.  
  462. //------------------------------------------------------------------------------
  463. // UpdateUserToken
  464. //------------------------------------------------------------------------------
  465.  
  466. void UpdateUserToken(Environment* ev, ODNameResolver* resolver,
  467.                         ODOSLToken* odToken, AEDesc* desc)
  468. {
  469.     ODDesc*    userODToken = resolver->GetUserToken(ev, odToken);
  470.     THROW_IF_ERROR(AEDescToODDesc(desc, userODToken));
  471.     THROW_IF_ERROR(AEDisposeDesc(desc));
  472. }
  473.  
  474. //------------------------------------------------------------------------------
  475. // CountEmbeddedParts
  476. //------------------------------------------------------------------------------
  477.  
  478. ODSLong CountEmbeddedParts(Environment* ev, ODPart* prt)
  479. {
  480.     if ( prt == kODAppShell ) return 1;
  481.  
  482.     ODSLong result = 0;
  483.     for ( TempODEmbeddedFramesIterator iter(ev,prt,kODNULL);
  484.             iter.Current(); iter.Next() )
  485.     {
  486.         ++result;
  487.     }
  488.     return result;
  489. }
  490.  
  491. //------------------------------------------------------------------------------
  492. // ODDisposeAppleEvent
  493. //------------------------------------------------------------------------------
  494.  
  495. OSErr ODDisposeAppleEvent( AppleEvent* aevt )
  496. {
  497.     (void)AEDisposeDesc( aevt );
  498.     return AEDisposeDesc( aevt );
  499. }
  500.  
  501.  
  502. //------------------------------------------------------------------------------
  503. // FrameFromStandardPartToken
  504. //------------------------------------------------------------------------------
  505.  
  506. ODFrame* FrameFromStandardPartToken(AEDesc* token)
  507. {
  508.     ODFrame* frame;
  509.     PartFrameFromStandardPartToken( token, kODNULL, &frame );
  510.     return frame;
  511. }
  512.  
  513. //------------------------------------------------------------------------------
  514. // PartFromStandardPartToken
  515. //------------------------------------------------------------------------------
  516.  
  517. ODPart* PartFromStandardPartToken(AEDesc* token)
  518. {
  519.     ODPart* part;
  520.     PartFrameFromStandardPartToken( token, &part, kODNULL );
  521.     return part;
  522. }
  523.  
  524. //------------------------------------------------------------------------------
  525. // PartFrameFromStandardPartToken
  526. //------------------------------------------------------------------------------
  527.  
  528. void PartFrameFromStandardPartToken(AEDesc* token, ODPart** part,
  529.         ODFrame** frame)
  530. {
  531.     ODBoolean coerced = kODFalse;
  532.      if ( token->descriptorType != kODStandardPartTokenType )    // dup. only if must
  533.     {
  534.         AEDesc coercedToken;
  535.         THROW_IF_ERROR( AECoerceDesc( token, kODStandardPartTokenType,
  536.                 &coercedToken ) );
  537.         coerced = kODTrue;
  538.         token = &coercedToken;
  539.     }
  540.     WASSERT(token->descriptorType == kODStandardPartTokenType);
  541.     WASSERT(token->dataHandle != kODNULL);
  542.     WASSERT( GetHandleSize(token->dataHandle) == sizeof(StandardPartToken) );
  543.     StandardPartToken spt = FIRSTBYTESFROMHANDLE(
  544.             token->dataHandle, StandardPartToken );
  545.     if ( part )
  546.         *part = spt.fPart;
  547.     if ( frame )
  548.         *frame = spt.fFrame;
  549.     if ( coerced )
  550.         (void)AEDisposeDesc( token );
  551. }
  552.  
  553. //------------------------------------------------------------------------------
  554. // CanBeStandardPartToken
  555. //------------------------------------------------------------------------------
  556.  
  557. ODBoolean CanBeStandardPartToken( AEDesc* token )
  558. {
  559.     ODBoolean result = (token->descriptorType == kODStandardPartTokenType) &&
  560.         (GetHandleSize(token->dataHandle) == sizeof(StandardPartToken));
  561.     if ( !result )
  562.     {
  563.         AEDesc coercedToken;
  564.         OSErr err = AECoerceDesc( token, kODStandardPartTokenType,
  565.                 &coercedToken );
  566.         result = (err == noErr) &&
  567.                 (coercedToken.descriptorType == kODStandardPartTokenType) &&
  568.                 (GetHandleSize(coercedToken.dataHandle)
  569.                         == sizeof(StandardPartToken));
  570.         (void)AEDisposeDesc( &coercedToken );
  571.     }
  572.     return result;
  573. }
  574.  
  575. //------------------------------------------------------------------------------
  576. // CreateStandardPartToken
  577. //------------------------------------------------------------------------------
  578.  
  579. OSErr CreateStandardPartToken( ODFrame* frame, ODPart* part, AEDesc* newToken )
  580. {
  581.     StandardPartToken    spt;
  582.     Environment*        ev = somGetGlobalEnvironment();
  583.     
  584.     // refcount the objects since we're saving them
  585.     if (frame)
  586.         frame->Acquire(ev);
  587.     if (part)
  588.         part->Acquire(ev);
  589.     
  590.     spt.fFrame = frame;
  591.     spt.fPart = part;
  592.     return AECreateDesc( kODStandardPartTokenType, &spt, sizeof(spt), newToken );
  593. }
  594.  
  595. //------------------------------------------------------------------------------
  596. // GetDefaultRootFrame
  597. //------------------------------------------------------------------------------
  598.  
  599. ODFrame* GetDefaultRootFrame(Environment *ev, ODSession* session)
  600. {
  601.     ODWindow* odWindow = session->GetWindowState(ev)->AcquireFrontRootWindow(ev);
  602.     ODFrame* rootFrame = odWindow ? odWindow->GetRootFrame(ev) : kODNULL;
  603.     ODReleaseObject(ev, odWindow);
  604.     return rootFrame;
  605. }
  606.  
  607. //------------------------------------------------------------------------------
  608. // ShouldHandleEvent
  609. //------------------------------------------------------------------------------
  610.  
  611. pascal ODBoolean ShouldHandleEvent(    ODPart*            part,
  612.                                     ODAppleEvent*    message,
  613.                                     ODAppleEvent*    reply,
  614.                                     ODSession*        session)
  615. {
  616.     ODError                error = noErr;
  617.     ODOSLToken*            oslToken;
  618.     ODDesc*                userToken = kODNULL;
  619.     ODPart*                contextPart = kODNULL;
  620.     ODPart*                realPart = kODNULL;
  621.     ODFrame*            contextFrame;
  622.     AEDesc                realEvent = {typeNull, kODNULL};
  623.     AEDesc                obj = {typeNull, kODNULL};
  624.     Environment*        ev = somGetGlobalEnvironment();
  625.     ODNameResolver*        resolver = session->GetNameResolver(ev);
  626.     ODBoolean            samePart = kODFalse;
  627.     ODBoolean            disposeToken = kODFalse;
  628.     
  629.     /*
  630.         This routine shows how to work around the fact that events without a 
  631.         direct parameter are sent first to the shell (which you'll never notice),
  632.         then to the root part (which you will notice if your part is also the root)
  633.         and then finally to the destination part specified in the subject attribute.
  634.         In addition, it shows how you can determine the destination frame.
  635.         
  636.         Normally, events are sent to the part containing the direct object.
  637.         This is typically the context of the token which OpenDoc replaces the
  638.         actual object specifier with.  So normally, you don't even need to look
  639.         at the direct parameter since you are the object which is handling the 
  640.         event.  However, in the case where the direct parameter is missing, or
  641.         where the direct parameter is a part reference (i.e. part "Bob",
  642.         part id 65535 or part 1 of part 1 of part 1), the dispatching is a bit
  643.         messy due to the fact that you typically want to send the event to the
  644.         container of the object (i.e. the part who contains the thing) so when
  645.         you refer to a part, the container of that part gets the message. Of
  646.         course, there are some caveats as for who "contains" whom.  Most notably,
  647.         a "part id 65535" reference is always "contained" by the root part since
  648.         OpenDoc doesn't walk the tree looking for the actual container.  That's
  649.         one of the reasons for this recipe.  In addition, it turns out that 
  650.         the subject attribute is almost always a part reference, so this 
  651.         case turns out to almost always be true when the direct parameter is
  652.         missing or is not an object which OpenDoc can resolve.
  653.         
  654.         Also, this code contains provisions for a change in OpenDoc's 
  655.         behavior as of 1.2.  Prior to 1.2, OpenDoc does not touch the subject
  656.         attribute while after 1.2 OpenDoc replaces the subject attribute with
  657.         the token it got when resolving the subject, just like it does with the
  658.         direct parameter.  This code copes with that scenario.
  659.         
  660.         Finally, this code exposes the details about the standard part token,
  661.         which is not made public in the OpenDoc interfaces.  Nevertheless, it
  662.         is necessary and accepted that people will be looking at standard part
  663.         tokens, so this is an acceptable way of dealing with life in the
  664.         SemanticInterface.
  665.     */
  666.     
  667.     TRY
  668.         ODDescToAEDesc(message, &realEvent);
  669.         
  670.         // create an ODOSLToken (which is essentially an ODDesc)
  671.         oslToken = new ODOSLToken;
  672.         THROW_IF_NULL(oslToken);
  673.         oslToken->InitODOSLToken(ev);
  674.         
  675.         // look for and/or at the direct parameter
  676.         error = AEGetKeyDesc(&realEvent, keyDirectObject, typeWildCard, &obj);
  677.         THROW_IF_ERROR( AEDescToODDesc(&obj, oslToken ) );
  678.         
  679.         // if it is missing or not a token then check the subject attribute
  680.         if (error != noErr || !resolver->IsODToken(ev, oslToken)) {
  681.             // there is no direct parameter or it is not an ODToken (i.e. we couldn't resolve it)
  682.             THROW_IF_ERROR( AEGetAttributeDesc(&realEvent, keySubjectAttr, typeWildCard, &obj) );
  683.             if (obj.descriptorType != typeObjectSpecifier) {
  684.                 // obj is a token or null
  685.                 AEDescToODDesc(&obj, oslToken);
  686.                 WASSERT(resolver->IsODToken(ev, oslToken) || 
  687.                         oslToken->GetDescType(ev) == typeNull);
  688.             }
  689.             else {
  690.                 // the subject was an object so we need to resolve it
  691.                 
  692.                 // create a wrapper ODObjectSpec (which is just an ODDesc)
  693.                 ODObjectSpec* objWrapper = new ODObjectSpec();
  694.                 THROW_IF_NULL(objWrapper);
  695.                 objWrapper->InitODObjectSpec(ev);
  696.  
  697.                 // copy the obj into the ODObjectSpec & dispose of the original
  698.                 THROW_IF_ERROR( AEDescToODDesc(&obj, objWrapper ) );
  699.                 THROW_IF_ERROR( AEDisposeDesc(&obj) );
  700.  
  701.                 // prepare the output ODOSLToken
  702.                 oslToken->SetDescType(ev, typeNull);
  703.                 
  704.                 // resolve the subject attribute & copy the token to obj
  705.                 resolver->Resolve(ev, objWrapper, oslToken, kODAppShell);
  706.                 THROW_IF_ERROR( ODDescToAEDesc(oslToken, &obj) );
  707.     
  708.                 ODDeleteObject(objWrapper);
  709.                 disposeToken = kODTrue;
  710.             }
  711.         }
  712.         // At this point both obj & oslToken contain the same data, 
  713.         // the token obtained from resolving either the direct parameter
  714.         // or the subject attribute.
  715.         WASSERT(obj.descriptorType == oslToken->GetDescType(ev));    // a cheap check
  716.         
  717.         if (obj.descriptorType != typeNull && obj.dataHandle != kODNULL) {
  718.             // there is an object, so we need to figure out if it is a 
  719.             // standard part token and get the part and frame from it or
  720.             // if not, get the context of the token, which should be our part.
  721.             ASSERT(resolver->IsODToken(ev, oslToken), 23);
  722.             userToken = resolver->GetUserToken(ev, oslToken);
  723.             ODDescToAEDesc(userToken, &obj);
  724.             // CanBeStandardPartToken allows developers to make their own tokens
  725.             // which can be coerced into standard part tokens.
  726.             if (CanBeStandardPartToken(&obj)) {
  727.                 // A standard part token is merely a part and frame reference, but
  728.                 // this routine allows us to hide that info from this code.
  729.                 PartFrameFromStandardPartToken(&obj, &contextPart, &contextFrame);
  730.             }
  731.             else {
  732.                 // This context was saved during the object resolution and should
  733.                 // be the part and frame which contains the object referenced.
  734.                 resolver->GetContextFromToken( ev, oslToken, &contextPart, &contextFrame);
  735.             }
  736.             // If we have a frame, then try getting the real part from the part wrapper.
  737.             if (contextFrame) {
  738.                 TRY
  739.                     realPart = contextPart->GetRealPart(ev);
  740.                     samePart = ODObjectsAreEqual(ev, realPart, part);
  741.                     contextPart->ReleaseRealPart(ev);
  742.                 CATCH_ALL
  743.                     WARN("Couldn't get real part, error == %d", ErrorCode());
  744.                 ENDTRY
  745.             }
  746.         }
  747.         else {
  748.             // Since we have a null reference, we must be the root frame
  749.             // because without a reference, we can't target anyone else.
  750.             samePart = kODTrue;
  751.         }
  752.         
  753. //        WARN("%sHandle - part = %x, wrapper = %x, frame = %x", 
  754. //                samePart ? "" : "Don't ", part, contextPart, contextFrame);
  755.  
  756.         // At this point, if samePart is true, then we're supposed to handle this event.
  757.     CATCH_ALL
  758.         error = ErrorCode();
  759.     ENDTRY
  760.     
  761.     AEDisposeDesc(&realEvent);
  762.     AEDisposeDesc(&realEvent);
  763.     AEDisposeDesc(&obj);
  764.     if (disposeToken)
  765.         resolver->DisposeToken(ev, oslToken);
  766.     else
  767.         ODDeleteObject(oslToken);    
  768.     return samePart;
  769. }    // ShouldHandleEvent
  770.  
  771. /*******************************************************************************
  772.  *    CompareDescs
  773.  *
  774.  *    Compare two descriptors of the same type.  We have a list of known types
  775.  *    and valid operations.  Invalid types and operations ASSERT and then return
  776.  *    kODFalse.  All operations are desc1 operation desc2, in that order.
  777.  *    
  778.  *******************************************************************************
  779.  */
  780. ODBoolean
  781. CompareDescs(const AEDesc *desc1, ODDescType operation, const AEDesc *desc2)
  782. {
  783.     char        *p1, *p2;
  784.     long        i, len, len1, len2, theSize;
  785.     Boolean        result;
  786.     DescType    theKey = typeNull;
  787.     DescType    theType, ignoreThis;
  788.     AEDesc        coerced = {typeNull, kODNULL};
  789.     AEDesc        copy1 = {typeNull, kODNULL};
  790.     AEDesc        copy2 = {typeNull, kODNULL};
  791.     AEDesc        *myDesc1;
  792.     AEDesc        *myDesc2;
  793.     AppleEvent    event;
  794.     AEDesc        ignoreThese;
  795.     ODBoolean    considerCase;
  796.     
  797.     result = kODFalse;
  798.     /* coerce desc2 into same type as desc1 if necessary */
  799.     if (desc1->descriptorType != desc2->descriptorType) {
  800.         TRY
  801.             THROW_IF_ERROR(AECoerceDesc(desc2, desc1->descriptorType, &coerced));
  802.             myDesc2 = &coerced;
  803.         CATCH_ALL
  804.             myDesc2 = kODNULL;
  805.         ENDTRY;
  806.         if (myDesc2 == kODNULL)
  807.             return kODFalse;
  808.     }
  809.     else
  810.         myDesc2 = (AEDesc *)desc2;
  811.     myDesc1 = (AEDesc *)desc1;
  812.     /* either original or coerced copy will be in myDesc2 */
  813.     WASSERT(myDesc1->descriptorType == myDesc2->descriptorType);
  814.     /* Compare lists - recursive comparison iff they are the same length */
  815.     if (myDesc1->descriptorType == typeAEList) {
  816.         THROW_IF_ERROR(AECountItems(myDesc1, &len1));
  817.         THROW_IF_ERROR(AECountItems(myDesc2, &len2));
  818.         switch (operation) {
  819.             case kAEEquals:
  820.             {
  821.                 if (len1 != len2)
  822.                     return kODFalse;
  823.                 for (i = 1; i <= len1; i++) {
  824.                     THROW_IF_ERROR(AEGetNthDesc(myDesc1, i, typeWildCard, &theKey, ©1));
  825.                     THROW_IF_ERROR(AEGetNthDesc(myDesc2, i, typeWildCard, &theKey, ©2));
  826.                     result = CompareDescs(©1, operation, ©2);
  827.                     THROW_IF_ERROR(AEDisposeDesc(©1));
  828.                     THROW_IF_ERROR(AEDisposeDesc(©2));
  829.                     if (!result)
  830.                         return kODFalse;
  831.                 }
  832.                 return kODTrue;
  833.             }
  834.             case kAEContains:
  835.             {
  836.                 if (len1 == 0)
  837.                     return (len1 == len2);
  838.                 if (len2 == 1) {
  839.                     WASSERT(desc2->descriptorType != typeAEList);
  840.                     for (i = 1; i <= len1; i++) {
  841.                         THROW_IF_ERROR(AEGetNthDesc(myDesc1, i, typeWildCard, &theKey, ©1));
  842.                         result = CompareDescs(©1, operation, desc2);
  843.                         THROW_IF_ERROR(AEDisposeDesc(©1));
  844.                         if (result)
  845.                             return kODTrue;
  846.                     }
  847.                     return kODFalse;
  848.                 }
  849.                 else {
  850.                     for (i = 1; i <= len2; i++) {
  851.                         THROW_IF_ERROR(AEGetNthDesc(myDesc2, i, typeWildCard, &theKey, ©2));
  852.                         result = CompareDescs(myDesc1, operation, ©2);
  853.                         THROW_IF_ERROR(AEDisposeDesc(©2));
  854.                         if (result)
  855.                             return kODTrue;
  856.                     }
  857.                     return kODFalse;
  858.                 }
  859.             }
  860.             default:
  861.                 return kODFalse;
  862.         }
  863.     }
  864.     
  865.     /*    We assume all data types are contiguous streams of bytes
  866.      *    and do byte by byte comparisons in all cases.  This 
  867.      *    results in case sensitive text comparisons, so we'll
  868.      *    uppercase copies of both descs.
  869.      */
  870.     if (myDesc1->descriptorType == typeChar) {
  871.         // check the current considering clauses
  872.         considerCase = kODTrue;
  873.         TRY
  874.             THROW_IF_ERROR( AEGetTheCurrentEvent(&event) );
  875.             if (event.dataHandle != kODNULL) {
  876.                 THROW_IF_ERROR( AEGetAttributeDesc(&event, enumConsiderations, typeAEList, &ignoreThese) );
  877.                 // if list contains kAECase then we should uppercase things
  878.                 THROW_IF_ERROR( AECountItems(&ignoreThese, &len) );
  879.                 for ( i = 1; i <= len; ++i) {
  880.                     THROW_IF_ERROR( AEGetNthPtr(&ignoreThese, i, typeEnumeration, &theKey, &theType, 
  881.                             &ignoreThis, sizeof(ignoreThis), &theSize) );
  882.                     if (ignoreThis == kAECase)
  883.                         considerCase = kODFalse;
  884.                 }
  885.             }
  886.         CATCH_ALL
  887.             WARN("Unexpected error #%d in CompareDescs", ErrorCode());
  888.         ENDTRY
  889.         if (!considerCase) {
  890.             UppercaseText(*myDesc1->dataHandle, GetHandleSize(myDesc1->dataHandle), smCurrentScript);
  891.             UppercaseText(*myDesc2->dataHandle, GetHandleSize(myDesc2->dataHandle), smCurrentScript);
  892.         }
  893.     }
  894.     switch (operation) {
  895.         case kAEEquals:
  896.         {
  897.             if ((len = GetHandleSize(myDesc1->dataHandle)) != 
  898.                         GetHandleSize(myDesc2->dataHandle)) {
  899.                 result = kODFalse;
  900.                 goto Finish;
  901.             }
  902.             p1 = (char *) *myDesc1->dataHandle;
  903.             p2 = (char *) *myDesc2->dataHandle;
  904.             for (i = 1; i <= len; i++) {
  905.                 if (*p1++ != *p2++) {
  906.                     result = kODFalse;
  907.                     goto Finish;
  908.                 }
  909.             }
  910.             result = kODTrue;
  911.             break;
  912.         }
  913.         case kAEGreaterThan:
  914.         case kAEGreaterThanEquals:
  915.         case kAELessThan:
  916.         case kAELessThanEquals:
  917.         {
  918.             len1 = GetHandleSize(myDesc1->dataHandle);
  919.             len2 = GetHandleSize(myDesc2->dataHandle);
  920.             len = len1 < len2 ? len1 : len2;
  921.             p1 = (char *) *myDesc1->dataHandle;
  922.             p2 = (char *) *myDesc2->dataHandle;
  923.             for (i = 1; i <= len; i++) {
  924.                 if (*p1 != *p2) {
  925.                     switch (operation) {
  926.                         case kAEGreaterThan:
  927.                         case kAEGreaterThanEquals:
  928.                             result = (*p1 > *p2);
  929.                             goto Finish;
  930.                         case kAELessThan:
  931.                         case kAELessThanEquals:
  932.                             result = (*p1 < *p2);
  933.                             goto Finish;
  934.                     }
  935.                 }
  936.                 p1++;
  937.                 p2++;
  938.             }
  939.             switch (operation) {
  940.                 case kAEGreaterThan:
  941.                     result = (len1 > len2);
  942.                     goto Finish;
  943.                 case kAEGreaterThanEquals:
  944.                     result = (len1 >= len2);
  945.                     goto Finish;
  946.                 case kAELessThan:
  947.                     result = (len1 < len2);
  948.                     goto Finish;
  949.                 case kAELessThanEquals:
  950.                     result = (len1 <= len2);
  951.                     goto Finish;
  952.             }
  953.             WASSERT(0);
  954.         }
  955.         case kAEBeginsWith:    /* 1 begins with 2 */
  956.         {
  957.             char    oldState;
  958.             
  959.             len1 = GetHandleSize(myDesc1->dataHandle);
  960.             len2 = GetHandleSize(myDesc2->dataHandle);
  961.             if (len2 > len1) {
  962.                 result = kODFalse;
  963.                 goto Finish;
  964.             }
  965.             oldState = HGetState(myDesc2->dataHandle);
  966.             HLock(myDesc2->dataHandle);
  967.             result = Munger(myDesc1->dataHandle, 0, *myDesc2->dataHandle, len2, kODNULL, 0) == 0;
  968.             HSetState(myDesc2->dataHandle, oldState);
  969.             break;
  970.         }
  971.         case kAEEndsWith:    /* 1 ends with 2 */
  972.         {
  973.             char    oldState;
  974.             
  975.             len1 = GetHandleSize(myDesc1->dataHandle);
  976.             len2 = GetHandleSize(myDesc2->dataHandle);
  977.             if (len2 > len1) {
  978.                 result = kODFalse;
  979.                 goto Finish;
  980.             }
  981.             oldState = HGetState(myDesc2->dataHandle);
  982.             HLock(myDesc2->dataHandle);
  983.             result = Munger(myDesc1->dataHandle, 0, *myDesc2->dataHandle, len2, kODNULL, 0) == len1 - len2;
  984.             HSetState(myDesc2->dataHandle, oldState);
  985.             break;
  986.         }
  987.         case kAEContains:    /* 1 contains 2 */
  988.         {
  989.             char    oldState;
  990.             
  991.             len1 = GetHandleSize(myDesc1->dataHandle);
  992.             len2 = GetHandleSize(myDesc2->dataHandle);
  993.             if (len2 > len1) {
  994.                 result = kODFalse;
  995.                 goto Finish;
  996.             }
  997.             oldState = HGetState(myDesc2->dataHandle);
  998.             HLock(myDesc2->dataHandle);
  999.             result = Munger(myDesc1->dataHandle, 0, *myDesc2->dataHandle, len2, kODNULL, 0) >= 0;
  1000.             HSetState(myDesc2->dataHandle, oldState);
  1001.             break;
  1002.         }
  1003.     }
  1004. Finish:
  1005.     AEDisposeDesc(&coerced);
  1006.     AEDisposeDesc(©1);
  1007.     AEDisposeDesc(©2);
  1008.     return result;
  1009. }
  1010.  
  1011.